From: Maciej Trela <maciej.trela [at] intel.com>
Add support for non-grow reshape operation - i.e. when changing the layout only.
The operation for changing the layout is needed for Raid0->Raid5 migrations:
after Raid0 is taken over to Raid4 it has to be reshaped to the new layout to become Raid5.
Operation sequence for non-grow reshape is the same as for OLCE (online capacity expansion) reshape type:
- update_super() with "update_grow_array" parameter
- prepare_update() with "update_grow_array"
- process_update() with "update_grow_array"
Note that for Raid5 layout we need to provide additional missing device to metadata - see process_update().
Signed-off-by: Maciej Trela <maciej.trela [at] intel.com>
---
Grow.c | 42 ++++++++++++++++++++++++++++++++++
managemon.c | 12 +++++-----
super-intel.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++----------
3 files changed, 106 insertions(+), 19 deletions(-) mode change 100644 => 100755 super-intel.c
diff --git a/Grow.c b/Grow.c
index ea6f266..4146a05 100644
--- a/Grow.c
+++ b/Grow.c
[at] [at] -1624,6 +1624,9 [at] [at] int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
/* prepare meta update and add devices to mdmon
*/
info.delta_disks = delta_disks;
+ info.new_chunk = nchunk;
+ info.new_layout = nlayout;
+ info.new_level = (level == UnSet) ? array.level : level;
st->update_tail = &st->updates;
if (st->ss->update_super(st, &info, "update_grow_array",
info.name, 0, 0, NULL) > 0)
[at] [at] -1667,6 +1670,13 [at] [at] native_array_setup:
break;
}
} else {
+ struct mdinfo info;
+ int delta_disks = 0;
+ int container_fd = -1;
+ int dn;
+ struct mdinfo *ret_info = NULL;
+ int required_disks = 0;
+
/* set them all just in case some old 'new_*' value
* persists from some earlier problem
*/
[at] [at] -1690,6 +1700,38 [at] [at] native_array_setup:
fprintf(stderr, " Bitmap must be removed before shape can be changed\n");
break;
}
+
+ /* check if we have external or native metadata
+ */
+ if (st == NULL || st->ss->external == 0)
+ goto ext_array_configured;
+
+ /* update array for external meta via user space
+ */
+ dn = devname2devnum(sra->text_version + 1);
+ container_fd = open_dev_excl(dn);
+ if (container_fd < 0)
+ goto ext_array_configured;
+ st->ss->load_super(st, container_fd, NULL);
+ close(container_fd);
+ st->ss->getinfo_super(st, &info);
+
+ delta_disks = 0;
+ strcpy(info.sys_name, sra->sys_name);
+ ret_info = st->ss->container_content(st);
+ if (ret_info == NULL)
+ goto ext_array_configured;
+ required_disks = ndisks;
+
+ /* prepare meta update and add devices to mdmon
+ */
+ info.delta_disks = delta_disks;
+ info.new_chunk = nchunk;
+ info.new_layout = nlayout;
+ info.new_level = (level == UnSet) ? array.level : level;
+ st->update_tail = &st->updates;
+ st->ss->update_super(st, &info, "update_grow_array",
+ info.name, 0, 0, NULL);
}
ext_array_configured:
diff --git a/managemon.c b/managemon.c
index 8a4e089..a60aa97 100644
--- a/managemon.c
+++ b/managemon.c
[at] [at] -380,9 +380,6 [at] [at] static void manage_member(struct mdstat_ent *mdstat,
* trying to find and assign a spare.
* We do that whenever the monitor tells us too.
*/
- // FIXME
- a->info.array.chunk_size = mdstat->chunk_size;
- // MORE
level = mdstat_to_level(mdstat);
if (a->info.array.level != level && level >= 0) { [at] [at] -396,8 +393,9 [at] [at] static void manage_member(struct mdstat_ent *mdstat,
/* not takeover fo maybe OLCE
* accept OLCE during reshape only
*/
- if ((a->info.array.raid_disks < mdstat->raid_disks) &&
- (a->info.array.raid_disks > 0)) {
+ if ((a->info.array.raid_disks < mdstat->raid_disks && a->info.array.raid_disks > 0) ||
+ (a->info.array.chunk_size != mdstat->chunk_size && a->info.array.chunk_size > 0) ||
+ (a->info.array.layout != mdstat->layout && a->info.array.layout >
+0)) {
/* Yes - online capacity expanssion
*/
if (a->container->ss->grow_array) {
[at] [at] -417,6 +415,8 [at] [at] static void manage_member(struct mdstat_ent *mdstat,
}
}
a->info.array.raid_disks = mdstat->raid_disks;
+ a->info.array.chunk_size = mdstat->chunk_size;
+ a->info.array.layout = mdstat->layout;
if (a->check_degraded) {
struct metadata_update *updates = NULL; [at] [at] -515,7 +515,7 [at] [at] static void manage_new(struct mdstat_ent *mdstat,
return;
mdi = sysfs_read(-1, mdstat->devnum,
- GET_LEVEL|GET_CHUNK|GET_DISKS|GET_COMPONENT|
+ GET_LEVEL|GET_LAYOUT|GET_CHUNK|GET_DISKS|GET_COMPONENT|
GET_DEGRADED|GET_DEVS|GET_OFFSET|GET_SIZE|GET_STATE);
new = malloc(sizeof(*new));
diff --git a/super-intel.c b/super-intel.c old mode 100644 new mode 100755 index faa5d2e..286f722
--- a/super-intel.c
+++ b/super-intel.c
[at] [at] -1753,7 +1753,7 [at] [at] static int update_super_imsm(struct supertype *st, struct mdinfo *info,
}
if ((strcmp(update, "update_grow_array") == 0) &&
- (info->delta_disks > 0)) {
+ (info->delta_disks >= 0)) {
struct imsm_update_grow_array *u = NULL;
struct mdinfo *sra = NULL;
struct mdinfo *vol = NULL;
[at] [at] -1808,6 +1808,12 [at] [at] static int update_super_imsm(struct supertype *st, struct mdinfo *info,
disks = (disks > map->num_members) ?
disks : map->num_members;
+ /* Support non-grow reshape case:
+ * if reshaping raid5(4) additional missing disk will be used */
+ if (map->raid_level == 0 && info->new_level == 5
+ && info->new_layout == 0)
+ disks++;
+
/* allocate device that can receive new disks number
* and reserve place for second map during migration
*/
[at] [at] -1815,7 +1821,6 [at] [at] static int update_super_imsm(struct supertype *st, struct mdinfo *info,
((disks - 1) * sizeof(__u32)) +
sizeof(struct imsm_map) + ((disks-1) * sizeof(__u32));
u = calloc(1, len);
-
if (u == NULL) {
dprintf("imsm: Error: Cannot allocate memory for update (mdadm: update_grow_array)\n");
return 1;
[at] [at] -1885,6 +1890,12 [at] [at] static int update_super_imsm(struct supertype *st, struct mdinfo *info,
spare = NULL;
}
+ /* Support non-grow reshape case:
+ * if reshaping raid5(4) additional missing disk will be used */
+ if (map_new->raid_level == 0 && info->new_level == 5
+ && info->new_layout == 0)
+ map_new->num_members++;
+
/* migration has to be in progress,
* to get second map, copy it from current device map
*/
[at] [at] -1898,13 +1909,6 [at] [at] static int update_super_imsm(struct supertype *st, struct mdinfo *info,
map = get_imsm_map(dev_new, 0);
disks = map->num_members - map_migr_new->num_members;
- if (disks != u->reshape_delta_disks) {
- /* wrong number of disks added to md
- */
- dprintf("imsm: ERROR: Not enough drives added to md (added = %i, required = %i).\n",
- disks, u->reshape_delta_disks);
- goto exit_update_grow_array;
- }
/* update ready,
* append it
[at] [at] -5210,10 +5214,16 [at] [at] int imsm_grow_array(struct active_array *a, int new_raid_disks)
inst, a->info.array.raid_disks, a->info.array.level);
/* grow support only */
- if ((a->info.array.raid_disks >= new_raid_disks) &&
+ if ((a->info.array.raid_disks > new_raid_disks) &&
(new_raid_disks > 0))
return ret_val;
+ /* support non-grow reshape */
+ if (a->info.array.raid_disks == new_raid_disks) {
+ ret_val = 1;
+ goto do_not_grow;
+ }
+
/* Look for all disks beyond current configuration
* To handle degradation after takeover
* look also on last disk in configuration.
[at] [at] -5309,6 +5319,7 [at] [at] int imsm_grow_array(struct active_array *a, int new_raid_disks)
/* prepare device to receive new disk(s)
*/
+ do_not_grow:
reallocate_imsm_dev(super, inst, new_raid_disks);
return ret_val;
[at] [at] -5438,8 +5449,9 [at] [at] static void imsm_process_update(struct supertype *st,
int slot;
int update_grow_array_status = -1;
+
slot = u->slot;
- if (u->reshape_delta_disks <= 0) {
+ if (u->reshape_delta_disks < 0) {
fprintf(stderr, "error:(imsm) "\
"Wrong update is passed\n");
goto update_grow_array_exit;
[at] [at] -5515,6 +5527,38 [at] [at] static void imsm_process_update(struct supertype *st,
migr_map_src = get_imsm_map(dev_new, 1);
memcpy(migr_map, migr_map_src, sizeof_imsm_map(migr_map_src));
+ /* Support non-grow reshape case:
+ * if reshaping raid5(4) additional missing disk will be used */
+ if (map->raid_level != a->info.array.level) {
+ if (map->raid_level == 0 &&
+ a->info.array.level == 5 &&
+ a->info.array.layout == 0) {
+
+ int i;
+ map->raid_level = a->info.array.level;
+ mpb->num_disks++;
+
+ /* clear missing disks list */
+ while (super->missing) {
+ dl = super->missing;
+ super->missing = dl->next;
+ __free_imsm_disk(dl);
+ }
+ find_missing(super);
+ dl = super->missing;
+ assert(dl != NULL);
+ if (!dl)
+ break;
+ memset(&dl->disk, 0, sizeof(dl->disk));
+ strcpy((char *)dl->disk.serial, "MISSING");
+ dl->disk.total_blocks = map->blocks_per_member;
+ /* Set slot for missing disk */
+ i = map->num_members - 1;
+ set_imsm_ord_tbl_ent(map, i, dl->index | IMSM_ORD_REBUILD);
+ dl->raiddisk = i;
+ }
+ }
+
/* manage size, if active array is known
* to in line with md access active array
* (Initialize pointer to the proper active array) [at] [at] -5844,7 +5888,7 [at] [at] static void imsm_prepare_update(struct supertype *st,
dprintf("prepare_update(): update_grow_array\n");
- if (u->reshape_delta_disks <= 0)
+ if (u->reshape_delta_disks < 0)
break;
/* add place for device in device list [at] [at] -6008,7 +6052,8 [at] [at] int imsm_reshape_is_allowed_on_container(struct is_allowed_params *params)
}
st->ss->getinfo_super(st, &info);
- if (params->raid_disks <= info.array.raid_disks) {
+ if (params->raid_disks <= info.array.raid_disks &&
+ params->raid_disks) {
/* we work on container for
* Online Capacity Expansion
* only
--
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo [at] vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
